#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>


char cmd_line[1024]; //用于接收存储整条命令
char* cmd_param[32]; //将整条命令拆解成一个个参数
char env_buffer[64]; //环境变量缓冲区

//shell运行原理：父进程接收并解析命令，创建子进程执行命令，父进程等待。
int main(){
  //0.命令行解释器是常驻内存进程，不退出
  while(1)
  {
    //1.打印提示信息：[root@localhost myshell]#
    printf("[root@localhost myshell]# ");
    fflush(stdout);
    //sleep(1);
    //2.获取用户输入（包括指令和选项）："ls -a -l -i"
    memset(cmd_line, '\0', sizeof(cmd_line));    
    if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL) continue;
    if(strcmp(cmd_line, "\n") == 0) continue;
    cmd_line[strlen(cmd_line)-1] = '\0';
    //printf("%s\n", cmd_line);
    //3.命令行字符串解析："ls -a -l" --> "ls" "-a" "-l"
    cmd_param[0] = strtok(cmd_line, " ");
    int i = 1;
    while((cmd_param[i++] = strtok(NULL, " "))); //多加一层圆括号防止高亮
    //for(int i = 0; cmd_param[i]; ++i)
    //{
    //  printf("%s ",cmd_param[i]);
    //}
    //printf("\n");
    //4.内置命令：让父进程（shell）自己执行的指令，又叫内建命令
    //内建命令本身就是shell中的一个函数调用
    if(strcmp(cmd_param[0], "cd") == 0)
    {
      if(cmd_param[1] != NULL)
      chdir(cmd_param[1]); 
      continue;
    }
    if(strcmp(cmd_param[0], "export") == 0)
    {
      if(cmd_param[1] != NULL)
      {
        strcpy(env_buffer, cmd_param[1]);
        putenv(env_buffer);
      }
      continue;
    }
    //5.创建子进程执行命令：
    int id = fork();
    if(id == 0)
    {
      printf("I'm child process! pid:%d ppid:%d\n", getpid(), getppid());
      execvp(cmd_param[0], cmd_param);
      exit(1);
    }

    int status = 0;
    int ret = waitpid(-1, &status, 0);
    if(ret > 0)
    {
      if(WIFEXITED(status))
      {
        printf("normal exit! child_pid:%d exit_code:%d\n", ret, WEXITSTATUS(status));
      }
      else
      {
        printf("abnormal exit! child_pid:%d exit_signal:%d\n", ret, status&0x7F);
      }
    }
    else if(ret < 0)
    {
      printf("Waiting failed!\n");
    }
  }
}
